/**
 * You may think you know what the following code does.
 * But you dont. Trust me.
 * Fiddle with it, and youll spend many a sleepless
 * night cursing the moment you thought youd be clever
 * enough to "optimize" the code below.
 * Now close this file and go play with something else.
 */
/**
 * 你可能会认为你读得懂以下的代码。但是你不会懂的，相信我吧。
 * 要是你尝试玩弄这段代码的话，你将会在无尽的通宵中不断地咒骂自己为什么会认为自己聪明到可以优化这段代码。
 * 现在请关闭这个文件去玩点别的吧。
 */
import { MapWrap } from "../../../Core/FrameEx/ES5Ex";
import GParam from "../../../Core/GEvent/GParam";
import GChild from "../../../Core/GView/GChild";
import { GNodePool } from "../../../Core/Manager/GNodePool";
import MathEx from "../../../Core/Math/MathEx";
import { MapLayer, PART_BTL_SCENE } from "../../Common/Define";
import { Res } from "../../Common/UIResources";
import JXRBCmdMgr from "../../Views/JXBattle/JXRBCmdMgr";
import JXRBFlags from "../../Views/JXBattle/JXRBFlags";
import GameMgr from "../GameMgr";
import { PRIORITY_VIEW } from './../../../Core/CoreDefine';
import { GCtrl } from './../../../Core/GCtrl';
import { CMsg, GRID_TYPE, INFO_TYPE } from './../../Common/Define';
import BtlFightLayer from "./BtlFighltLayer";
import BtlMapConverts from "./BtlMapCanverts";
import BtlMapElement from "./BtlMapElement";
import { BtlMapParser, MapParseProgress, MapParseStatus } from './BtlMapParser';
import BtlMapTouchLayer from "./BtlMapTouchLayer";



declare interface NodeOpt {
	size?: cc.Size;
	anchor?: cc.Vec2;
}
/**节点池 */
class CNodePool extends GNodePool {
	protected _opt: NodeOpt;
	constructor(parent?: cc.Node, opt?: NodeOpt) {
		super(parent);
		this._opt = opt;
	}
	syncCreate() {
		let node = new cc.Node();
		if (this._opt.size) node.setContentSize(this._opt.size);
		if (this._opt.anchor) node.setAnchorPoint(this._opt.anchor);
		// node.group = GCtrl.CameraGroup.map;;
		return node;
	}
	asyncCreate(cb: NodeCallBack) {
		let node = this.syncCreate();
		cb(node);
	}
}

declare interface SpriteOpt {
	type?: cc.Sprite.Type;
	sizeMode?: cc.Sprite.SizeMode;
	trim?: boolean;
	src?: cc.macro.BlendFactor;
	dst?: cc.macro.BlendFactor;
	size?: cc.Size;
	anchor?: cc.Vec2;
}

/**精灵池 */
class CSpritePool extends GNodePool {
	protected _opt: SpriteOpt;
	constructor(parent?: cc.Node, opts?: SpriteOpt) {
		super(parent);
		this._opt = opts;
	}

	syncCreate() {
		let node = new cc.Node();
		let sp = node.addComponent(cc.Sprite);
		if (this._opt.size) node.setContentSize(this._opt.size);
		if (this._opt.anchor) node.setAnchorPoint(this._opt.anchor);
		if (this._opt.type != null) sp.type = this._opt.type;
		if (this._opt.sizeMode != null) sp.sizeMode = this._opt.sizeMode;
		if (this._opt.trim != null) sp.trim = this._opt.trim;
		if (this._opt.src != null) sp['srcBlendFactor'] = this._opt.src;
		return node;
	}

	asyncCreate(cb: NodeCallBack) {
		let node = this.syncCreate();
		cb(node);
	}
}

const SCALE_MIN = 1.1; // 缩放系数越大。视野越小
const SCALE_MAX = 0.9;

/**默认加速度 */
const DefaultAcceleration = 2000;
/**最大熟读 */
const MaxSpeed = 4000;
/** 防抖动处理 */
const DRAW_CHECK_DISTANCE = 3

/** 必要条件初始化状态 */
const INIT_FLAG = {
	/** 地图静态资源 */
	STATIC: 1 << 0,
	/** 摄像机准备 */
	CAMERA: 1 << 1,
	/**戰鬥 */
	BATTLE: 1 << 2,
	/** 准备完成 */
	ALL: 1 << 0 | 1 << 1 | 1 << 2,
}

enum VisitState {
	/** 不进行渲染 */
	VSIdle,
	/** 第一次渲染地图 */
	VSInit,
	/** 采用更新模式更新地图 */
	VSUpdate,
}

const { ccclass, property, menu } = cc._decorator;
@ccclass @menu("View/Fight/BtlCameraMap")
export default class BtlCameraMap extends GChild {
	/** 地图摄像机 */
	@property(cc.Camera) camera: cc.Camera = null;
	/**对象层 */
	@property(cc.Node) objectLayer: cc.Node = null;
	/**效果层 */
	@property(cc.Node) UIRoot2d: cc.Node = null;
	/**地图层 */
	@property(cc.Node) mapLayer: cc.Node = null;
	/**触摸层 */
	@property(cc.Node) touchLayer: cc.Node = null;
	/**战斗层 */
	@property(cc.Node) fightLayer: cc.Node = null;

	@property(cc.Sprite) ground: cc.Sprite = null;

	@property(cc.Sprite) border: cc.Sprite = null;
	@property(cc.Sprite) bottom: cc.Sprite = null;
	@property() mapGridSize: cc.Size = cc.size(0);

	@property(cc.Node) heroLayer: cc.Node = null;
	/*小麦数量 */
	@property(cc.Label) wheat: cc.Label = null;

	@property(cc.Label) level: cc.Label = null;
	@property(cc.Label) bool: cc.Label = null;
	@property(cc.Label) wave: cc.Label = null;
	@property(cc.Node) close: cc.Node = null;

	/** 用来标识所有条件是否准备完成 */
	protected _initFlag = 0;
	/**地图触摸层 */
	protected _touchLayer: BtlMapTouchLayer = null;
	/**戰鬥層級 */
	protected _fightLayer: BtlFightLayer = null;
	/** 地图层级节点 */
	protected _layers: MapWrap<number, cc.Node> = new MapWrap();
	/** 地图节点缓存池 */
	protected _layerPools: MapWrap<number, GNodePool> = new MapWrap();


	/** 地图沙盘大小 */
	protected _mapSize: cc.Size;
	public get mapSize(): cc.Size { return this._mapSize; }
	/** 元素Size(用于位置计算) */
	protected _unitSize: cc.Size = null;
	public get unitSize(): cc.Size { return this._unitSize; }

	/** 元素Size（用于大小计算） */
	protected _gridSize: cc.Size = null;
	public get gridSize(): cc.Size { return this._gridSize; }
	/** 地图绘制区域 */
	protected _lastVerts: [cc.Vec2, cc.Vec2, cc.Vec2, cc.Vec2];
	public miniTcgPos: cc.Vec2;
	/**可视区域 */
	protected _visitRect: cc.Rect = null;
	public get visitRect(): cc.Rect {
		return this._visitRect;
	}

	/** 选中标志（当前选中的对象） */
	protected _selected: BtlMapElement;

	///////////////////逻辑变量以及事件/////////////////////////
	//绘制状态
	protected _drawState: VisitState = VisitState.VSIdle;
	//活动item容器
	protected _elementComponents: MapWrap<number, BtlMapElement> = new MapWrap<number, BtlMapElement>();
	//回收的item容器
	protected _recoverComponents: Array<BtlMapElement> = new Array<BtlMapElement>();
	/** 地图坐标转换器 */
	protected _convert: BtlMapConverts;
	public get convert(): BtlMapConverts {
		return this._convert;
	}
	/*地图数据加载类 */
	public _parser: BtlMapParser = null;
	/** 地图数据 */
	public get static(): BtlMapParser { return this._parser; };
	public set static(parse: BtlMapParser) {
		this._parser = parse;
		this._initConfigure();
	}

	public mapRaw: SMapDataRaw = null;
	public mapStyle: SMapStyleDataRaw = null;
	///////////////////触摸控制/////////////////////////
	/**是否点击 */
	protected _click = false;
	/**是否触摸 */
	protected _touch = false;
	public get touch(): boolean { return this._touch; }
	/**是否处于移动 */
	protected _bMove = false
	/*触摸偏移 */
	protected _touchDrawDelta: cc.Vec2 = cc.Vec2.ZERO
	/**上次触摸时间 */
	protected _lastTouchTimes: number[] = [];
	/**触摸点 */
	protected _lastTouchPoints: cc.Vec2[] = [];
	/**清除记录点的定时器 */
	protected _staticCheckTimer = -1;
	/**移动速度 */
	protected _speed: number = 0;
	/**移动偏量 */
	protected _moveDelta = cc.v2(0, 0);
	/**加速度 */
	protected _bSpeedAddState = false;
	/**默认加速度 */
	protected _acceleration = DefaultAcceleration;
	protected _winArgs: any = null;
	/////////////////节点池///////////////////////
	//精灵池
	private _spritePool: cc.NodePool = new cc.NodePool();
	private _NodePool: cc.NodePool = new cc.NodePool();
	public _cmdMgr: JXRBCmdMgr;

	public _flags: JXRBFlags;

	///////////////////////////////////////////////////////////////////////////// 生命周期 //////////////////////////////////////////////////////////////////////

	onGLoad() {
		// 创建地图数据解析类
		let mapId = GameMgr.mapMgr.mapId
		this.mapRaw = GameMgr.mapData.getRaw<SMapDataRaw>(mapId);
		this.mapStyle = GameMgr.mapStyle.getRaw(this.mapRaw.style);
		this.assetImpl.spriteFrame(this.bottom, Res.bigpic.map + "bottom" + this.mapStyle.id);
		this.assetImpl.spriteFrame(this.ground, Res.bigpic.map + "ground" + this.mapStyle.id);
		this.assetImpl.spriteFrame(this.border, Res.bigpic.map + "border" + this.mapStyle.id);
	}

	public startLoadData() {
		let root = "map/mapData" + this.mapRaw.map;
		this._parser = new BtlMapParser(root, (mpp: MapParseProgress, mps: MapParseStatus, parser: BtlMapParser) => {
			if (mpp === MapParseProgress.MPP_LoadMapData && mps === MapParseStatus.MPS_LoadSuccess) {
				this.static = parser;
				this.allReady(INIT_FLAG.STATIC);
				this._fightLayer.fightInit(this._winArgs, (cmd: JXRBCmdMgr) => {
					this._cmdMgr = cmd;
					this.allReady(INIT_FLAG.BATTLE)
				});
			}
		}, this.assetImpl)
		this._parser.loadMapData();
		GameMgr.mapMgr._fsMapPatser = this._parser;
	}

	/*初始化戰鬥層級 */
	public setBattle(winArgs: ArgsBattleViewCtrl<any>) {
		this._fightLayer = this.fightLayer.addComponent(BtlFightLayer);
		this._fightLayer.heroContent = this.heroLayer;
		this._fightLayer.wheatNode = this.wheat.node.parent;
		this._fightLayer.bool = this.bool;

		this._fightLayer.level = this.level;
		this._winArgs = winArgs;
		if (winArgs.sceneId === PART_BTL_SCENE.GUANQIA) {
			let arg = winArgs as ArgsBattleViewCtrl<SceneGuanQia>;
			let level1 = GameMgr.lUserData.level < 1;
			let level2 = GameMgr.lUserData.level < 2;
			if ((arg.args.level === 1 && level1) || (arg.args.level === 2 && level2)) {
				this.close.active = false
			}
		}
	}

	start() {
		this.allReady(INIT_FLAG.CAMERA);
	}

	onGDestroy() {
		// 删除所有对象，和引用
		this._recoverComponents.forEach(ele => {
			ele.layerElements.values().forEach((node: cc.Node) => {
				node.destroy();
			})
		});
		for (let i = 0; i < this._spritePool.size(); i++) {
			this._spritePool.get().destroy();
		}
		for (let i = 0; i < this._NodePool.size(); i++) {
			this._NodePool.get().destroy();
		}
	}

	update(dt) {
		this._drawState && this._drawElement();
		// this.onAutoMove(dt);
	}


	///////////////////////////////////////////////////////////////////////////// 初始化配置 //////////////////////////////////////////////////////////////////////
	protected changeWeathNum() {
		this.wheat.string = this._cmdMgr.wheat.toString();
	}

	protected onRetreatClick() {
		GCtrl.ES.emit(CMsg.client.fight_ui.onRetreatClick);
	}

	/**初始配置*/
	protected _initConfigure() {
		this._mapSize = this._parser.mapSize;
		this._unitSize = this._parser.unitSize;
		this._gridSize = this._parser.gridSize;
		let winSize = cc.winSize;
		//建立比视图 稍微大的 矩形绘制区域
		this._visitRect = cc.rect(-winSize.width * 0.25, -winSize.height * 0.25, cc.winSize.width * 1.5, cc.winSize.height * 1.5);
		//初始化坐标转化器
		this._convert = new BtlMapConverts(this.objectLayer, cc.v2(this.gridSize.width / 2, this.gridSize.height / 2), this._mapSize, null, this._unitSize)
	}

	/** 都准备好了，整是开始流程 */
	protected allReady(curReadyFlag: number) {
		this._initFlag |= curReadyFlag;
		if (this._initFlag != INIT_FLAG.ALL) return;
		this._initTouchEvent();
		this._initEvent();
		this._cmdMgr.btlCameraMap = this;
		this._cmdMgr.btlMapConverts = this.convert;
		this._cmdMgr._wave = this.wave;
		this._drawState = VisitState.VSInit;
		this._cmdMgr.startCmd();
	}

	/**监听事件 */
	protected _initEvent() {
		GCtrl.ES.on(CMsg.client.fight_ui.selectItem, this, this.setGridSelect.bind(this), PRIORITY_VIEW)
		GCtrl.ES.on(CMsg.client.fight_ui.hideAllItem, this, this.hideAll.bind(this), PRIORITY_VIEW)
		GCtrl.ES.on(CMsg.client.fight_ui.onWheatChange, this, this.changeWeathNum.bind(this))
	}

	//初始 触摸层
	protected _initTouchEvent() {
		let touchLayer = this.touchLayer;
		let mapTouchLayer = touchLayer.addComponent(BtlMapTouchLayer);
		mapTouchLayer.map = this;
		this._touchLayer = mapTouchLayer;
	}

	///////////////////////////////////////////////////////////////////////////// 地图操作 //////////////////////////////////////////////////////////////////////
	/**从节点池获取节点 */
	public getNodeFromPool(type): cc.Node {
		switch (type) {
			case MapLayer.MLMaterial: {
				if (this._spritePool.size()) {
					return this._spritePool.get();
				} else {
					let node = new cc.Node();
					node.addComponent(cc.Sprite);
					node.scale = this._parser.itemsScale
					return node;
				}
			}
		}
	}

	/**回收节点到节点池 */
	public recoverNodeToPool(node: cc.Node) {
		node.removeFromParent();
		switch (Number(node.name)) {
			case MapLayer.MLMaterial: {
				node.scaleY = 1;
				node.scaleX = 1;
				node.zIndex = 0;
				node.getComponent(cc.Sprite).spriteFrame = null;
				this._spritePool.put(node);
				break
			}
		}
	}
	/** 绘制地图 */
	protected _drawElement() {
		if (this._drawState == VisitState.VSInit) {
			this._initVisited();
		}
		else if (this._drawState == VisitState.VSUpdate) {
			// //回收
			this._recoverVisited();
			this._initVisited();
		}
		this._drawState = VisitState.VSIdle;
	}

	/** 绘制 */
	protected _initVisited() {
		//获取 4个顶点在 地图坐标的位置
		let verts = this.getMVisitVerts();
		this._lastVerts = verts;
		this.miniTcgPos = verts[0];
		//获取所有在矩形区域内的所有 地图坐标
		MathEx.getViewRectangleCoods(verts, (mapPos: cc.Vec2) => {
			if (mapPos.x > this.mapSize.width - 1 || mapPos.y > this.mapSize.height - 1 || mapPos.x < 0 || mapPos.y < 0) {
				return;
			}
			let data = this.static.getElementData(mapPos);
			if (data) {
				let element = this._elementComponents.get(data.id);
				if (element) {
					return;
				}
				// 获取每个层级的节点
				element = this.createElement(data.zIndex);
				element.tcgPos = mapPos;
				element.id = data.id;
				element.data = data;
				this._elementComponents.set(data.id, element);
				this._onElementActive(element);

			}
		})
		if (this._flags) {
			this._cmdMgr.jxBtlAns.setFalgs(this._flags);
		}
	}

	/**创建 地图单元 */
	protected createElement(index: number) {
		let layers = [MapLayer.MLGrid, MapLayer.MLMaterial, MapLayer.MLEffect_2]; // maplayer.muidisplay
		let element = this._recoverComponents.pop()
		if (!element) {
			element = new BtlMapElement(this.assetImpl);
		}
		element.cameraMap = this;
		for (let i = 0; i < layers.length; i++) {
			let pool = this._getLayerPool$Create(layers[i]);
			let node = pool.pop();
			node.zIndex = index + i;
			let type = layers[i];
			element.layerElements.set(type, node);
		}
		return element;
	}

	/**回收视野外的地块 */
	protected _recoverVisited() {
		this._elementComponents.rforEach((item, key) => {
			let itemRect = item.rect();
			//判断矩形是否相交 不想交就回收
			if (!this._visitRect.intersects(itemRect)) {
				this.recoverItem(item, key);
			}
		});
	}

	/**
	 * 回收单元节点
	 * @param item 
	 * @param key 
	 */
	protected recoverItem(item: BtlMapElement, key: number) {
		item.onRecover();
		item.layerElements.forEach((node, type) => {
			let pool = this.getLayerPool(type);
			pool.push(node);
		});
		item.layerElements.clear();
		this._recoverComponents.push(item);
		this._elementComponents.delete(key);
	}

	/**地块在可视区域中调用 */
	protected _onElementActive(element: BtlMapElement) {
		element.onActive();
	}


	/** 获取绘制区域的四个顶点 */
	public getMVisitVerts(): [cc.Vec2, cc.Vec2, cc.Vec2, cc.Vec2] {
		return [
			this.n2m(cc.v2(this._visitRect.xMin, this._visitRect.yMax), true), // lt,
			this.n2m(cc.v2(this._visitRect.xMin, this._visitRect.yMin), true), // lb,
			this.n2m(cc.v2(this._visitRect.xMax, this._visitRect.yMin), true), // rb,
			this.n2m(cc.v2(this._visitRect.xMax, this._visitRect.yMax), true)  // rt,
		];
	}

	/** 将节点坐标转换为地图坐标 */
	public n2m(pos: cc.Vec2, bRound?: boolean): cc.Vec2 {
		return this._convert.converToMapPos(pos, bRound);
	}

	/** 地图坐标到世界坐标 */
	public m2w(pos: cc.Vec2): cc.Vec2 {
		let ccPos = this.m2n(pos);
		let world = this.node.convertToWorldSpaceAR(ccPos);
		return world;
	}

	/** 将地图坐标转换位节点坐标 */
	public m2n(pos: cc.Vec2 | number, posY?: number): cc.Vec2 {
		return this._convert.converToCCPos(pos, posY);
	}

	/////////////////////////////////////////////////////////////////////////////层级操作/////////////////////////////////////////////////////////////////////////////////

	/** 获取层级节点池，没有创建 */
	protected _getLayerPool$Create(type: MapLayer): GNodePool {
		// 其中的UI层不作为节点池,触摸层不作为节点池
		if (type == MapLayer.MLTouch || type == MapLayer.MElementUI || type == MapLayer.MLEffect_1) {
			return;
		}
		let pool = this._layerPools.get(type);
		if (!pool) {
			switch (type) {
				case MapLayer.MLEffect_2:
				case MapLayer.MLGrid: {
					pool = new CSpritePool(this._getLayer$Create(type), {
						type: cc.Sprite.Type.SIMPLE,
						sizeMode: cc.Sprite.SizeMode.CUSTOM,
						trim: true,
						size: new cc.Size(this.gridSize.width, this.gridSize.height),
						anchor: cc.v2(0.5, 0.5),
					});
					break;
				}
				case MapLayer.MLMaterial: {
					pool = new CNodePool(this._getLayer$Create(type), {
						size: new cc.Size(this.gridSize.width, this.gridSize.height),
						anchor: cc.v2(0.5, 0.5),
					})
					break;
				}
			}

			this._layerPools.set(type, pool);
		}
		return pool;
	}

	/** 获取层级节点池 */
	public getLayerPool<T extends GNodePool>(type: MapLayer): T {
		return this._layerPools.get(type) as T;
	}

	/** 获取层级，没有创建 */
	protected _getLayer$Create(type: MapLayer): cc.Node {
		let layer = this._layers.get(type);
		if (!layer) {
			layer = new cc.Node(MapLayer[type]);
			layer.zIndex = type;
			layer.anchorX = 0;
			layer.anchorY = 0;
			layer.position = cc.Vec2.ZERO;
			layer.parent = this.objectLayer;
			this._layers.set(type, layer);
		}
		return layer;
	}

	/** 获取层级 */
	public getLayer(type: MapLayer) {
		if (type == MapLayer.MElementUI || MapLayer.MLEffect_1) {
			return this.UIRoot2d;
		}
		return this._getLayer$Create(type);
	}

	/**选中地块事件触发 */
	protected setGridSelect(_, param: GParam) {
		let info = param.get<SelectGridInfo>()
		let element = this._elementComponents.get(GameMgr.mapMgr.encodeXxyy(info.pos))
		if (!element || element.data.gridInfo[INFO_TYPE.GRID] != GRID_TYPE.PLACE) {
			this.hideAll();
			return;
		}
		this.setSelect(info.pos, info.heroId)
	}


	public selectGridByPos(pos: cc.Vec2) {
		return this._elementComponents.get(GameMgr.mapMgr.encodeXxyy(pos))
	}
	/**
	 *设置选中 
	 * @param coord 
	 */
	protected setSelect(coord: cc.Vec2, heroId: number) {
		if (!coord) {
			cc.error('coord is null!');
			return;
		}
		let raw = GameMgr.heroData.getRaw<SHeroDataRaw>(heroId)
		let element = this._elementComponents.get(GameMgr.mapMgr.encodeXxyy(coord));
		if (!element) return;
		if (this._selected && this._selected != element) {
			this._selected.onDisSelect();
			this.toggoleIsAtk(GameMgr.mapMgr.decodeXxyy(this._selected.id), false, raw.scope)
		}

		this._selected = element;
		this._selected.onSelect();
		this.toggoleIsAtk(coord, true, raw.scope)
	}

	/**隱藏取消所有選中 */
	protected hideAll() {
		if (this._selected) {
			this._selected.onDisSelect();
			this._elementComponents.forEach((ele: BtlMapElement, key) => {
				if (ele) {
					ele.isAttack(false);
				}
			})
		}
	}

	/**切換進攻地塊的隱藏*/
	protected toggoleIsAtk(coord: cc.Vec2, isAtk: boolean, id) {
		let atkGrids = GameMgr.mapMgr.getAdjacent(id, coord);
		atkGrids.forEach((coord) => {
			let element = this._elementComponents.get(GameMgr.mapMgr.encodeXxyy(coord))
			if (element) {
				element.isAttack(isAtk);
			}
		})
	}

	/**获取选中节点 */
	public getSelectNode(): cc.Node {
		let selectNode = this.getLayer(MapLayer.MLEffect_1).getChildByName('Efct');
		if (!selectNode) {
			selectNode = new cc.Node();
			let sp = selectNode.addComponent(cc.Sprite);

			this.assetImpl.spriteAtlasFrame(sp, Res.texture.map.material, "select");
			selectNode.name = "Efct"
			selectNode.parent = this.getLayer(MapLayer.MLEffect_1);
			selectNode.setContentSize(this.unitSize)
		}
		selectNode.scale = this._parser.itemsScale;
		return selectNode;
	}


}